package pl.un4giv3n.mightvsmagic.utils;

import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.Query;

import pl.un4giv3n.mightvsmagic.entity.Clan;
import pl.un4giv3n.mightvsmagic.entity.ClanWar;
import pl.un4giv3n.mightvsmagic.entity.User;

public final class ClanStatsUtil {
	private ClanStatsUtil(){}
	private static Map<Long, ClanStats> cache = new HashMap<Long, ClanStats>();
	private static final Comparator<Clan> FIGHTS_WON_COMPARATOR = new FightsWonComparator();
	private static final Comparator<Clan> FIGHTS_LOST_COMPARATOR = new FightsLostComparator();
	private static final Comparator<Clan> GOLD_WON_COMPARATOR = new GoldWonComparator();
	private static final Comparator<Clan> GOLD_LOST_COMPARATOR = new GoldLostComparator();
	public static final Comparator<Clan> NAME_COMPARATOR = new NameComparator();
	private static final Comparator<Clan> WARS_WON_COMPARATOR = new WarsWonComparator();
	private static final Comparator<Clan> WARS_LOST_COMPARATOR = new WarsLostComparator();
	private static final Comparator<Clan> MEMBER_COUNT_COMPARATOR = new MemberCountComparator();
	
	public static Map<Long, ClanStats> getCachedStats(){
		return Collections.unmodifiableMap(cache);
	}
	
	public static Map<Long, ClanStats> getAllClanStats(EntityManager em){
		refreshCache(em);
		return Collections.unmodifiableMap(cache);
	}
	
	public static ClanStats getClanStats(Clan clan, EntityManager em){
		refreshCache(em);
		return cache.get(clan.getId());
	}
	@SuppressWarnings("unchecked")
	public static void refreshCache(EntityManager em) {
		Query query = em.createNamedQuery("find.all.clans");
		List<Clan> clans = query.getResultList();
		for (Clan clan : clans) {
			refreshClanStats(em, clan);
		}
	}

	private static synchronized void refreshClanStats(EntityManager em, Clan clan) {
		cache.put(clan.getId(), getFreshClanStats(clan, em));
	}
	
	@SuppressWarnings("unchecked")
	public static ClanStats getFreshClanStats(Clan clan,EntityManager em) {
		ClanStats clanStats = new ClanStats();
		clanStats.setMemberCount(clan.getUsers().size());
		for (User user : clan.getUsers()) {
			UserStats userStats = StatsUtil.getFreshUserStats(user, em);
			clanStats.addFightsLost(userStats.getFightsLost());
			clanStats.addFightsWon(userStats.getFightsWon());
			clanStats.addGoldWon(userStats.getGoldWon());
			clanStats.addGoldLost(userStats.getGoldLost());
		}
		Query query = em.createNamedQuery("find.old.clan.wars");
		query.setParameter("clanId", clan.getId());
		List<ClanWar> wars = query.getResultList();
		int warsWon = 0;
		int warsLost = 0;
		for (ClanWar war : wars) {
			if(war.getWinnerId().longValue() == clan.getId().longValue()){
				warsWon++;
			}else{
				warsLost++;
			}
		}
		clanStats.setWarsLost(warsLost);
		clanStats.setWarsWon(warsWon);
		return clanStats;
	}
	
	public static void sort(List<Clan> users, String sortBy, String order){
		Comparator<? super Clan> comparator = getComparator(sortBy);
		Collections.sort(users, comparator);
		if("1".equals(order)){
			Collections.reverse(users);
		}
	}

	private static Comparator<? super Clan> getComparator(String sortBy) {
		Comparator<Clan> returnVal = NAME_COMPARATOR;
		if("fightsWon".equals(sortBy)){
			returnVal = FIGHTS_WON_COMPARATOR;
		}
		if("fightsLost".equals(sortBy)){
			returnVal = FIGHTS_LOST_COMPARATOR;
		}
		if("goldWon".equals(sortBy)){
			returnVal = GOLD_WON_COMPARATOR;
		}
		if("goldLost".equals(sortBy)){
			returnVal = GOLD_LOST_COMPARATOR;
		}
		if("warsLost".equals(sortBy)){
			returnVal = WARS_LOST_COMPARATOR;
		}
		if("warsWon".equals(sortBy)){
			returnVal = WARS_WON_COMPARATOR;
		}
		if("memberCount".equals(sortBy)){
			returnVal = MEMBER_COUNT_COMPARATOR;
		}
		return returnVal;
	}
	
	private static class FightsWonComparator implements Comparator<Clan>{
		
		@Override
		public int compare(Clan o1, Clan o2) {
			long thisVal = cache.get(o1.getId()).getFightsWon();
			long anotherVal = cache.get(o2.getId()).getFightsWon();
			return (thisVal<anotherVal ? -1 : (thisVal==anotherVal ? 0 : 1));
		}
	}
	private static class FightsLostComparator implements Comparator<Clan>{
		
		@Override
		public int compare(Clan o1, Clan o2) {
			long thisVal = cache.get(o1.getId()).getFightsLost();
			long anotherVal = cache.get(o2.getId()).getFightsLost();
			return (thisVal<anotherVal ? -1 : (thisVal==anotherVal ? 0 : 1));
		}
	}
	private static class GoldWonComparator implements Comparator<Clan>{
		
		@Override
		public int compare(Clan o1, Clan o2) {
			double thisVal = cache.get(o1.getId()).getGoldWon();
			double anotherVal = cache.get(o2.getId()).getGoldWon();
			return Double.compare(thisVal, anotherVal);
		}
	}
	private static class GoldLostComparator implements Comparator<Clan>{
		
		@Override
		public int compare(Clan o1, Clan o2) {
			double thisVal = cache.get(o1.getId()).getGoldLost();
			double anotherVal = cache.get(o2.getId()).getGoldLost();
			return Double.compare(thisVal, anotherVal);
		}
	}
	private static class NameComparator implements Comparator<Clan>{
		
		@Override
		public int compare(Clan o1, Clan o2) {
			String thisVal = o1.getName();
			String anotherVal = o2.getName();
			return thisVal.compareTo(anotherVal);
		}
	}
	private static class WarsLostComparator implements Comparator<Clan>{
		
		@Override
		public int compare(Clan o1, Clan o2) {
			long thisVal = cache.get(o1.getId()).getWarsLost();
			long anotherVal = cache.get(o2.getId()).getWarsLost();
			return (thisVal<anotherVal ? -1 : (thisVal==anotherVal ? 0 : 1));
		}
	}
	private static class WarsWonComparator implements Comparator<Clan>{
		
		@Override
		public int compare(Clan o1, Clan o2) {
			long thisVal = cache.get(o1.getId()).getWarsWon();
			long anotherVal = cache.get(o2.getId()).getWarsWon();
			return (thisVal<anotherVal ? -1 : (thisVal==anotherVal ? 0 : 1));
		}
	}
	private static class MemberCountComparator implements Comparator<Clan>{
		
		@Override
		public int compare(Clan o1, Clan o2) {
			long thisVal = o1.getUsers().size();
			long anotherVal = o2.getUsers().size();
			return (thisVal<anotherVal ? -1 : (thisVal==anotherVal ? 0 : 1));
		}
	}

}
